/* GMClient.cc -- Cliente GEARMedula
 *
 * Copyright (C) 2008, Diogo F. S. Ramos <diogo.ramos@usp.br>
 * GEAR - Grupo de Estudos Avançados em Robótica
 * <http://www.sel.eesc.usp.br/gear>
 *
 * This file is part of GEARMedula.
 * 
 * GEARMedula is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 3 of the
 * License.
 * 
 * GEARMedula is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <netdb.h>
#include <stdint.h>

#include <iostream>
#include <sstream>
#include <string>

#include "RPCTranslator.hh"
#include "Messages.hh"
#include "GMClient.hh"

using namespace std;

GMClient::GMClient()
{
}

GMClient::~GMClient()
{
    close( server_socket_ );
}

int
GMClient::Init( const string addr, const int port )
{
    // Iniciando o socket de conexão
    server_socket_ = socket( PF_INET, SOCK_STREAM, 0 );

    // Iniciando estrutura com informações do servidor
    InitSocketAddr( &server_socket_name_,
                    addr.c_str(),
                    port);

    if( connect( server_socket_,
                 (struct sockaddr *) &server_socket_name_,
                 sizeof( server_socket_name_) ) < 0 )
    {
        fprintf( stderr, "Não foi possível conectar ao servidor %s.",
                      addr.c_str());
    }

    rpc_translator_.Init( received_data_buffer_,
                          sended_data_buffer_ );
    
    return 0;
}

void
GMClient::InitSocketAddr( struct sockaddr_in *name,
                          const char *hostname,
                          uint16_t port)
{
    struct hostent *hostinfo;
     
    name->sin_family = AF_INET;
    name->sin_port = htons (port);
    hostinfo = gethostbyname (hostname);
    if (hostinfo == NULL)
    {
        fprintf( stderr,  "Host desconhecido %s.", hostname);
    }
    name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
}


int
GMClient::setField( const vector<float> field )
{
    MessageType message_type = MESSAGETYPE_SET_FIELD;
    int number_of_parameters = 1;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);

    for( int i = 0 ; i < kFieldVectorLength ; i++ )
    {
        arguments_passed[0].field_field_vector[i]= field[i];
    }
    
    SendCommand( message_type,
                 arguments_passed );    
    
    return 0;
}


int
GMClient::getField( std::vector<float> &field )
{
    MessageType message_type = MESSAGETYPE_GET_FIELD;
    std::vector<struct FieldContainer> arguments_vector;
    SendCommand( message_type,
                 arguments_vector );
    
    ReceiveCommand( message_type,
                    arguments_vector );

    for( int i = 0 ; i < kFieldVectorLength ; i++ )
    {
        field[i] = arguments_vector[0].field_field_vector[i];
        printf("field[%d] = %f\n", i, field[i] );
    }
    
    return 0;
}


int
GMClient::setWorld( const vector<float> world )
{
    MessageType message_type = MESSAGETYPE_SET_WORLD;
    int number_of_parameters = 1;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);

    for( int i = 0 ; i < kWorldVectorLength ; i++ )
    {
        arguments_passed[0].field_world_vector[i]= world[i];
    }
    
    SendCommand( message_type,
                 arguments_passed );    
    
    return 0;
}


int
GMClient::getWorld( std::vector<float> &world )
{
    MessageType message_type = MESSAGETYPE_GET_WORLD;
    std::vector<struct FieldContainer> arguments_vector;
    SendCommand( message_type,
                 arguments_vector );
    
    ReceiveCommand( message_type,
                    arguments_vector );

    for( int i = 0 ; i < kWorldVectorLength ; i++ )
    {
        world[i] = arguments_vector[0].field_world_vector[i];
        printf("world[%d] = %f\n", i, world[i] );
    }

    return 0;
}

int
GMClient::SetVel( const int id, const float vx, const float vy, const float va )
{
    MessageType message_type = MESSAGETYPE_SET_VEL;
    int number_of_parameters = 4;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);
    arguments_passed[0].field_integer = id;
    arguments_passed[1].field_float = vx;
    arguments_passed[2].field_float = vy;
    arguments_passed[3].field_float = va;

    SendCommand( message_type,
                 arguments_passed );    
    
    return 0;
}

int
GMClient::Kick( const int id, const int nivel )
{
    MessageType message_type = MESSAGETYPE_KICK;
    int number_of_parameters = 2;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);
    arguments_passed[0].field_integer = id;
    arguments_passed[1].field_integer = nivel;

    SendCommand( message_type,
                 arguments_passed );    

    return 0;
}

int
GMClient::DribbleEnable(const int id, const bool enable )
{
    MessageType message_type = MESSAGETYPE_DRIBBLE_ENABLE;
    int number_of_parameters = 2;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);
    arguments_passed[0].field_integer = id;
    arguments_passed[1].field_integer = enable;

    SendCommand( message_type,
                 arguments_passed );    
    return 0;
}

int
GMClient::SayHello(const int id)
{
    return 0;
}

int
GMClient::RegisterRobotName(const int id, const string robot_name )
{
    MessageType message_type = MESSAGETYPE_REGISTER_ROBOT_NAME;
    int number_of_parameters = 2;
    std::vector<struct FieldContainer> arguments_passed(number_of_parameters);
    arguments_passed[0].field_integer = id;
    arguments_passed[1].field_string.assign(robot_name);

    SendCommand( message_type,
                 arguments_passed );    
    
    return 0;
}

void
GMClient::ReceiveMessage ()
{
    ssize_t bytes_read = read( server_socket_,
                               (void*) &received_data_buffer_,
                               kBufferSize);
    if (bytes_read < 0 )
        fprintf( stderr, "Não consegui receber a mensagem.");
}

void
GMClient::ReceiveCommand( MessageType message_type,
                          std::vector<struct FieldContainer> &arguments_passed )
{
    ReceiveMessage();

    rpc_translator_.Receive( &message_type,
                             arguments_passed,
                             RPCSIDE_CLIENT);
}


void
GMClient::SendCommand( MessageType message_type,
                       std::vector<struct FieldContainer> arguments_passed )
{
    rpc_translator_.Send( message_type,
                          arguments_passed,
                          RPCSIDE_CLIENT );
    SendMessage();
}


int
GMClient::SendMessage()
{
    int bytes_sent = 0;
    while( bytes_sent < kBufferSize )
    {
        int bytes_writen = 0;
        bytes_writen = send( server_socket_,
                             sended_data_buffer_,
                             kBufferSize,
                             0 );
        if( bytes_sent < 0 )
        {
            return -1;
        }
        bytes_sent += bytes_writen;
    }

    return 0;
}
